#ifndef LIBV4L_TAIIC_H_
#define LIBV4L_TAIIC_H_
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <errno.h>
#include <thread>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define CLEAR(x) std::memset(&(x), 0, sizeof(x))
// VI数据回调
typedef void(tViFrameDataCallback)(char *camtype, void *data, long length, long timestamp);

class TaiicV4l2
{
private:
    struct buffer
    {
        void *start;
        size_t length;
    };
    int width;            // 图像宽
    int height;           // 图像高
    int format;           // 图像格式
    int device_type;      // 设备类型
    int memoey_type;      // 内存获取类型
    int n_buffers;        // 映射buffer个数
    char *right_dev_name; // 右侧设备名称
    char *left_dev_name;  // 左侧设备名称
    int plane_n;          // 图像视频的面数

    v4l2_format fmt;     // 设置视频格式和参数
    v4l2_capability cap; // 获取与视频设备相关的功能和能力信息

    int right_fd = -1; // 相机右侧开机流
    int left_fd = -1;  // 相机左侧开机流

    v4l2_buffer rightBuf; // 描述视频缓冲区的属性和状态
    v4l2_buffer leftBuf;
    v4l2_requestbuffers req;                         // 从内核请求一定数量的缓冲区内存
    tViFrameDataCallback *viFrameDataCallback; // vi 数据回调

    buffer *rightBuffers = nullptr; // 应用空间
    buffer *leftBuffers = nullptr;

    v4l2_buf_type type; //
    v4l2_plane planes;
    struct timespec rightTs; // 图像时间戳
    struct timespec leftTs;

    struct timespec last_rightTs; // 图像时间戳
    struct timespec last_leftTs;

    bool is_right_capture = false; // 相机开启标志位
    bool is_left_capture = false;

private:
    void openDevice();      // 1. Open the device
    void queDeviceCap();    // 2. Query the device capabilities
    void setDeviceFormat(); // 3. Set the device format
    void allocateBuffer();  // 4. Allocate buffers
    void queBuffer();       // 5. Queue the buffers

public:
    // void setFd(int fdSet);
    TaiicV4l2();
    void setWidth(int widthSet);                   // 像素-宽
    void setHeight(int heightSet);                 // 像素-高
    void setFormat(int formatSet);                 // 图像格式
    void setBuffersN(int n_buffersSet);            // 内核空间映射个数
    void setRightDevName(char *right_dev_nameSet); // 设备名称
    void setLeftDevName(char *left_dev_nameSet);
    void setDeviceType(int device_typeSet); // 设备类型
    void setMemoryType(int memoey_typeSet); // 内存映射方法
    void setPlaneN(int plane_nSet);         // 视频帧数据的平面数量

    // void viFrameCallback(tViFrameDataCallback dataCallback);

    void initDevice();
    void startCapt(tViFrameDataCallback dataCallback); // 6. Start capturing
    
    void getFrame();                                   // 7. Capture frames
    void stopCapt();                                   // 8. Stop capturing
    void closeDevice();                                // 9. Close the device

    void threadFunction(); // 线程函数
};

//#define BUFFER_SIZE 38400 * 3840 // 缓冲区的长度,可以修改
class RingBuf_Taiic
{
private:
    long validLen;               // 已使用的数据长度
    char *pHead = NULL;      // 环形存储区的首地址
    char *pTail = NULL;      // 环形存储区的结尾地址
    char *pValid = NULL;     // 已使用的缓冲区的首地址
    char *pValidTail = NULL; // 已使用的缓冲区的尾地址
    

public:
    void initRingbuffer();
    long writeRingbuffer(char *buffer, long addLen);
    long readRingbuffer(char *buffer, long len);
    long getRingbufferValidLen(void);
    void releaseRingbuffer(void);
    long buffer_size;
};

#endif